/* TextInputWidget.js
 *
 * Copyright 2006, Tim Dwelle.
 *
 * Licensed under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in
 * compliance with the License.  You may obtain a copy of
 * the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in
 * writing, software distributed under the License is
 * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
 * CONDITIONS OF ANY KIND, either express or implied.  See
 * the License for the specific language governing
 * permissions and limitations under the License.
 *
 */

$package("dowry.widget");

/**
 * Object represenation of a UI widget that knows how to
 * handle text-related input fields, such as text fields,
 * password fields, and hidden fields.
 *
 */
$class("TextInputWidget").$extends("Widget").$as(
{
    /**
     * Gets the value of the bound element, represented as a
     * type appropriate for the element's datatype.
     *
     * @return  the value
     *
     */
    getValue : function()
    {
        var val = null;

        var ele = this.getElement();
        if (ele && !ele.disabled)
        {
            val = ele.value;

            // convert the raw value
            var dt = this.getDatatype();
            if (dt)
            {
                val = dt.toDatatype(val);
            }
        }

        return val;
    },

    /**
     * Sets the value of the bound element, using a type
     * appropriate for the element's datatype.
     *
     * @param val  the value to set
     *
     */
    setValue : function(val)
    {
        var ele = this.getElement();
        if (ele)
        {
            // convert the provided value
            var dt = this.getDatatype();
            if (dt)
            {
                val = dt.toFormattedString(val);
            }

            // can't have a text input with
            // a null value... use an empty
            // string instead
            if (val == null)
            {
                val = "";
            }

            ele.value = val;
        }
    },

    /**
     * When the TextInputWidget is started, associate an
     * event to validate the input.  This will also restrict
     * the field's input to the specified valid characters,
     * and set the maximum length on this field (if these
     * properties are provided via the associated datatype).
     *
     */
    start : function()
    {
        var ele = this.getElement();
        if (ele)
        {
            if (ele.type != "hidden")
            {
                this._addAsteriskIfRequired(ele);
            }

            // get the datatype configuration
            var dt = this.getDatatype();
            if (dt)
            {
                var cfg = dt.toConfiguration();
                if (cfg)
                {
                    // max length
                    if (cfg.maxLength)
                    {
                        ele.maxLength = Number(cfg.maxLength);
                    }

                    // valid chars
                    if (cfg.validChars)
                    {
                        Dowry.event.addEvent(ele, "keypress", this._restrict);
                    }
                }
            }

            // validation
            Dowry.event.addEvent(ele, "change", this.validate);
        }
    },

    /**
     * Validates the value of the widget, according to the
     * associated datatype, and updates the widget's error
     * message as appropriate.
     *
     */
    validate : function()
    {
        var ele = this.getElement();
        var dt = this.getDatatype();

        if (ele && !ele.disabled && dt)
        {
            try
            {
                var val = ele.value;
                val = dt.trim(val);
                var msg = dt.validate(val);
                this.setErrorMessage(msg);
            }
            catch(e)
            {
                if (e == dt.REMOTE_VALIDATE)
                {
                    // handle remote validation
                    var cfg = dt.toConfiguration();
                    cfg.id = ele.id;
                    cfg.value = val;
                    Dowry.remote.validate(cfg, this.setErrorMessage);
                }
                else
                {
                    throw e;
                }
            }
        }
    },

    /**
     * Restricts the field's input to only valid characters.
     *
     * @param e  the event object
     *
     */
    _restrict : function(e)
    {
        // for the time being... we will assume
        // there is nothing to restrict
        var ok = true;

        // get the event info
        e = e || window.event;
        var key = e.keyCode || e.which;

        // get associated
        var ele = this.getElement();
        var dt = this.getDatatype();
        if (ele && dt)
        {
            var cfg = dt.toConfiguration();
            if (cfg)
            {
                var validChars = cfg.validChars;

                // make sure we have a key pressed and a
                // list of valid chars... oh, and since
                // this event *may* fire regardless what
                // key was pressed... lets make sure
                // they are hitting a special keys like
                // backspace or enter
                if (key != null &&
                    typeof validChars == "string" &&
                    key > 31 &&
                    !e.ctrlKey &&
                    !e.altKey)
                {
                    // NOTE:
                    // onkeypress will not send function
                    // key presses, but onkeydown will...
                    // unfortunately, our char codes are
                    // different if we listen to keypress
                    // vs keydown (for instance, a '112'
                    // key code for onkeypress is a 'p'
                    // to the keypress event, but is a
                    // function key to the keydown event),
                    // so we gotta assume that this is
                    // attached to the keypress event.
                    // if not, we may get odd behavior!

                    // we know that it needs to be
                    // restricted now... assume the
                    // worst!
                    ok = false;

                    // loop through, looking for a match
                    for(var i=0; i < validChars.length; i++)
                    {
                        if (key == validChars.charCodeAt(i))
                        {
                            ok = true;
                            break;
                        }
                    }
                }

                // notify that the event has been
                // cancelled
                if (!ok)
                {
                    try
                    {
                        e.preventDefault();
                    }
                    catch(ex)
                    {
                    }

                    try
                    {
                        e.returnValue = false;
                    }
                    catch(ex)
                    {
                    }
                }
            }
        }
    }
});